home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr43 / sbdsp2b.zip / VOC2RPD.PAS < prev    next >
Pascal/Delphi Source File  |  1995-01-21  |  19KB  |  416 lines

  1. Program ConvertVOCRPD;
  2.  
  3. (**************************************************************************)
  4. (*                            Program VOC2RPD                             *)
  5. (*                       By: Romesh Prakashpalan                          *)
  6. (**************************************************************************)
  7. (*  This program will convert a VOC file to my RPD format (the specs have *)
  8. (* been given out with my SBDSP unit). This will eliminate any "noise"    *)
  9. (* you might get due to the fact that you are probably reading in VOC     *)
  10. (* data structures instead of pure RAW data.                              *)
  11. (*  Any questions or comments (or donations ;-) ) should be directed to:  *)
  12. (*    Romesh Prakashpalan (hacscb93@huey.csun.edu) <- Until 01/31/94.     *)
  13. (*     Note: After 01/31/94, my account at CSUN expires, so look in the   *)
  14. (*           comp.lang.pascal or alt.sb.programmer newsgroups, for my     *)
  15. (*           current address.                                             *)
  16. (**************************************************************************)
  17.  
  18. Uses SBDSP, Crt;
  19.  
  20. (**************************************************************************)
  21. (*  Revisions:                                                            *)
  22. (*    Version 1.0α: Just strips off the VOC file header, to reduce a bit  *)
  23. (*                  of the "popping" that occurs when played back as a RAW*)
  24. (*                  file. This was pretty lame!                           *)
  25. (*    Version 1.10: Converts the file pretty much with all VOC specific   *)
  26. (*                  information removed. However, repeat loops will only  *)
  27. (*                  iterate ONCE, and Silence blocks will be REMOVED from *)
  28. (*                  the VOC file. In future versions, I plan on adding    *)
  29. (*                  repeats manually, digital silence (if user specifies  *)
  30. (*                  it), but these are minor things.                      *)
  31. (*    Version 1.11: STOOPID MISTAKE FIXED!!!! Would not write header to   *)
  32. (*                  the beginning of the file, but rather to the END!!    *)
  33. (*    Version 1.12: Added Input/Output checking on files, instead of      *)
  34. (*                  the program giving a "run-time error", it gives a     *)
  35. (*                  suitable error message.                               *)
  36. (*    Version 1.13: Fixed a Block 9 error in conversion (Previously I     *)
  37. (*                  did not have any VOC files to test Block 9 conversion *)
  38. (*                  on, so I apologize!). At this point, most SERIOUS     *)
  39. (*                  conversion flaws should have been recognized.         *)
  40. (**************************************************************************)
  41. (* Future Revisions:                                                      *)
  42. (*  I hope to create support for 16-bit sound in the next versions of my  *)
  43. (* code, but this is dependant on when I will be able to get code to      *)
  44. (* program the Sound Blaster 16! Only then will I be able to implement    *)
  45. (* such a conversion, as my program is the only one which will read, or   *)
  46. (* even recognise an RPD file! (As far as I know)                         *)
  47. (**************************************************************************)
  48. (*  Note: To all of those who are using this file for the SBDSP unit that *)
  49. (*        I have given out: What do you think of my unit???, do you think *)
  50. (*        that I should create support for the Sound Blaster 16? I do not *)
  51. (*        think that I should charge anything for it, as that would make  *)
  52. (*        me as bad as Creative Labs, but I would willingly take a small  *)
  53. (*        donation ;-). That's all right, just as long as you are able to *)
  54. (*        use the code, I'm happy. Please let me know what you think about*)
  55. (*        the unit though!                                                *)
  56. (**************************************************************************)
  57.  
  58. type
  59.  
  60. (****************************************************************************)
  61. (* Channel method: 0 - Layed down Byte 1 - Channel 0, Byte 2 - Channel 1... *)
  62. (*                 1 - First Channel continuously for Size Bytes, then comes*)
  63. (*                     the Second Channel, etc...                           *)
  64. (****************************************************************************)
  65.   RPDHeader = Record
  66.                 Sig: Array [0..2] of Char; (* "RPD" *)
  67.                 Version: Word;             (* Version # *)
  68.                 DAC: Byte;                 (* 8/16/4/4.6/2/2.6, etc...*)
  69.                 Phase: Byte;               (* Mono=0, Stereo=1, Surround=2*)
  70.                 Freq: Word;                (* Sample Frequency *)
  71.                 Channels: Byte;            (* # of DIGITAL Channels *)
  72.                 ChannelMethod: Byte;       (* Method for laying down channels *)
  73.                 Size: LongInt;             (* Size of Sample *)
  74.                 Reserved: Array [0..31] of Byte;
  75.               end;
  76.  
  77.   VOCHeader = Record
  78.                 Sig:Array [0..$13] of Char;(* "Creative Voice File" *)
  79.                 Offset: Word;              (* Offset of first datablock in the*)
  80.                                            (* .VOC file.                      *)
  81.                 Version: Word;             (* Version # *)
  82.                 Version2s: Word;           (* 2's complement of version # plus*)
  83.                                            (* 1234h ex: 1.10 = 1129           *)
  84.               end;
  85.  
  86.   ThreeByte = Array [1..3] of Byte;
  87.  
  88.   Block1Type = Record                      (* Voice Data Block *)
  89.                 Length: ThreeByte;
  90.                 TimeConstant: Byte;        (* = 256 - 1000000/Sample Rate *)
  91.                 PackType: Byte;            (* 0 = 8-bit unpacked *)
  92.                                            (* 1 = 4-bit packed   *)
  93.                                            (* 2 = 2.6 bit packed *)
  94.                                            (* 3 = 2-bit packed   *)
  95.                end;
  96.   Block2Type = Record                      (* Voice Continuation *)
  97.                  Length: ThreeByte;
  98.                end;
  99.  
  100.   Block3Type = Record                      (* Silence block *)
  101.                  Length: ThreeByte;        (* Always 3 *)
  102.                  Pause: Word;              (* Pause period in sample bytes *)
  103.                  TimeConstant: Byte;
  104.                end;
  105.  
  106.   Block4Type = Record                      (* Marker Block *)
  107.                  Length: ThreeByte;
  108.                  MarkerValue: Word;
  109.                end;
  110.  
  111.   Block5Type = Record                      (* Ascii Text (null-terminated) *)
  112.                  Length: ThreeByte;
  113.                end;
  114.  
  115.   Block6Type = Record                      (* Repeat Loop *)
  116.                  Length: ThreeByte;        (* Always 2 *)
  117.                  Count: Word;              (* 1 to $FFFE, $FFFF = endless loop*)
  118.                end;
  119.  
  120.   Block7Type = Record                      (* End Repeat Loop *)
  121.                  Length: ThreeByte;        (* Always 0 *)
  122.                end;
  123.  
  124.   Block8Type = Record                      (* Extended Block *)
  125.                  Length: ThreeByte;        (* Always 4 *)
  126.                  TimeConstant: Word;       (* For Mono:  *)
  127.                                            (* 65535-(256,000,000/sample rate)*)
  128.                                            (* For Stereo: *)
  129.                                            (* 65535-(256000000/sample rate*2) *)
  130.                  PackType: Byte;           (* Same as Block 1 *)
  131.                  Mode: Byte;               (* 0 = Mono, 1 = Stereo *)
  132.                end;
  133.  
  134.   Block9Type = Record                      (* NEW Extended VOC Block *)
  135.                  Length: ThreeByte;        (* Length of Sample + 12 (Bytes) *)
  136.                  SamplesPerSec: LongInt;   (* ACTUAL Samples/Second *)
  137.                  BitsPerSample: Byte;      (* Bits/Sample after compression *)
  138.                  Channels: Byte;           (* 1 for mono, 2 for stereo *)
  139.                  FormatTag: Word;          (* Format Tags follow: *)
  140.                                            (*   $000 - 8 bit unsigned PCM *)
  141.                                            (*   $001 - 4 Bit ADPCM *)
  142.                                            (*   $002 - 2.6 Bit ADPCM *)
  143.                                            (*   $003 - 2 Bit ADPCM *)
  144.                                            (*   $004 - 16 Bit Signed PCM *)
  145.                                            (*   $006 - CCITT a-Law *)
  146.                                            (*   $007 - CCITT u-Law *)
  147.                                            (*   $200 - 16 bit -> 4 Bit ADPCM *)
  148.                  Reserved: LongInt;        (* Reserved by Creative Labs *)
  149.                end;
  150. var
  151.   Source, Destination: String;
  152.   Ch: Char;
  153.  
  154. Function ThreeByte2Long (TheData: ThreeByte): LongInt;
  155. Begin
  156.   ThreeByte2Long := LongInt (TheData[1]) + LongInt (TheData[2]) shl 8 +
  157.                     LongInt (TheData[3]) shl 16;
  158. End;
  159.  
  160. Procedure ConvertVOC2RPD (Source, Destination: String);
  161. var
  162.   SourceF: File;
  163.   DestF: File;
  164.   TempRPDHead: RPDHeader;
  165.   TempVOCHead: VOCHeader;
  166.   TempBuffer: Pointer;
  167.   BlockType: Byte;
  168.   BytesConverted: LongInt;
  169.   Done: Boolean;
  170.   Block1: Block1Type;
  171.   Block2: Block2Type;
  172.   Block3: Block3Type;
  173.   Block4: Block4Type;
  174.   Block5: Block5Type;
  175.   Block6: Block6Type;
  176.   Block7: Block7Type;
  177.   Block8: Block8Type;
  178.   Block9: Block9Type;
  179.   LeftToGo: LongInt;
  180.   SkipNextBlock1: Boolean;
  181.  
  182. Begin
  183.   SkipNextBlock1 := False;
  184.   BytesConverted := 0;
  185.   Assign (SourceF, Source);
  186.   Assign (DestF, Destination);
  187.   Reset (SourceF, 1);
  188.   Rewrite (DestF, 1);
  189.   BlockRead (SourceF, TempVOCHead, SizeOf (TempVOCHead));
  190.   GetMem (TempBuffer, $FFFF);
  191.   TempRPDHead.Sig := 'RPD';
  192.   TempRPDHead.Version := 1;
  193.   TempRPDHead.Channels := 1;
  194.   TempRPDHead.ChannelMethod := 0;
  195.   (* Blank out the reserved field with 0's, so that future software won't *)
  196.   (* be confused!                                                         *)
  197.   FillChar (TempRPDHead.Reserved, SizeOf (TempRPDHead.Reserved), 0);
  198.   (* Write the incomplete header to the file, we shall update it later... *)
  199.   BlockWrite (DestF, TempRPDHead, SizeOf (TempRPDHead));
  200.   Done := False;
  201.   Repeat
  202.     BlockRead (SourceF, BlockType, SizeOf (BlockType));
  203.     Case BlockType of
  204.        0: Begin         (* Terminator Block *)
  205.             WriteLn ('Block Type 0 encountered, conversion complete...');
  206.             Done := True;
  207.           End;
  208.        1: Begin         (* Data Block *)
  209.             Write ('Converting Block Type 1.');
  210.             BlockRead (SourceF, Block1, SizeOf (Block1));
  211.             If not SkipNextBlock1 then
  212.             Begin
  213.               Case Block1.PackType of
  214.                 0: TempRPDHead.DAC := EightBitDMA;
  215.                 1: TempRPDHead.DAC := FourBitDMA;
  216.                 2: TempRPDHead.DAC := TwoSixBitDMA;
  217.                 3: TempRPDHead.DAC := TwoBitDMA;
  218.               end;
  219.               TempRPDHead.Freq := Round (1000000/(256 - Block1.TimeConstant));
  220.               TempRPDHead.Phase := 0;   (* Block Type 1 is ALWAYS MONO *)
  221.             End
  222.             Else SkipNextBlock1 := False;
  223.             Inc (BytesConverted, ThreeByte2Long (Block1.Length)-2);
  224.             LeftToGo := ThreeByte2Long (Block1.Length) - 2;
  225.             Repeat
  226.               If LeftToGo > $FFFF then
  227.               Begin
  228.                 Dec (LeftToGo, $FFFF);
  229.                 BlockRead (SourceF, TempBuffer^, $FFFF);
  230.                 BlockWrite (DestF, TempBuffer^, $FFFF);
  231.               End
  232.               Else
  233.               Begin
  234.                 BlockRead (SourceF, TempBuffer^, LeftToGo);
  235.                 BlockWrite (DestF, TempBuffer^, LeftToGo);
  236.                 LeftToGo := 0;
  237.               End;
  238.               Write ('.');
  239.             Until LeftToGo = 0;
  240.             WriteLn;
  241.             WriteLn ('Block Type 1: ', ThreeByte2Long (Block1.Length),
  242.                      ' bytes converted.');
  243.           end;
  244.           2: Begin      (* Voice Continuation *)
  245.                WriteLn ('Converting Block 2, Voice Continuation.');
  246.                BlockRead (SourceF, Block2, SizeOf (Block2));
  247.                Inc (BytesConverted, ThreeByte2Long (Block2.Length));
  248.                LeftToGo := ThreeByte2Long (Block2.Length);
  249.                Repeat
  250.                 If LeftToGo > $FFFF then
  251.                 Begin
  252.                   Dec (LeftToGo, $FFFF);
  253.                   BlockRead (SourceF, TempBuffer^, $FFFF);
  254.                   BlockWrite (DestF, TempBuffer^, $FFFF);
  255.                 End
  256.                 Else
  257.                 Begin
  258.                   BlockRead (SourceF, TempBuffer^, LeftToGo);
  259.                   BlockWrite (DestF, TempBuffer^, LeftToGo);
  260.                   LeftToGo := 0;
  261.                 End;
  262.                 Write ('.');
  263.               Until LeftToGo = 0;
  264.               WriteLn;
  265.               WriteLn ('Block Type 2: ', ThreeByte2Long (Block1.Length),
  266.                        ' bytes converted.');
  267.              end;
  268.           3: Begin      (* Silence Block, will be skipped *)
  269.                WriteLn ('Skipping a Silence Block (Block Type 3)');
  270.                BlockRead (SourceF, Block3, SizeOf (Block3));
  271.              end;
  272.           4: Begin      (* Marker Block *)
  273.                WriteLn ('Skipping a Marker Block (Block Type 4)');
  274.                BlockRead (SourceF, Block4, SizeOf (Block4));
  275.              End;
  276.           5: Begin      (* ASCII text *)
  277.                WriteLn ('Skipping embedded ASCII text (Block Type 5)');
  278.                BlockRead (SourceF, Block5, SizeOf (Block5));
  279.              End;
  280.           6: Begin      (* Repeat Loop, in version 1.10, they are skipped *)
  281.                WriteLn ('Skipping the repeat loop, loop will play ONCE');
  282.                BlockRead (SourceF, Block6, SizeOf (Block6));
  283.              End;
  284.           7: Begin      (* Signal the end of a repeat loop *)
  285.                WriteLn ('End of Repeat Loop found...');
  286.                BlockRead (SourceF, Block7, SizeOf (Block7));
  287.              End;
  288.           8: Begin      (* Extended Block (Stereo, and other 8-bit goodies) *)
  289.                WriteLn ('An extended block was found (8), reading data...');
  290.                SkipNextBlock1 := True;
  291.                BlockRead (SourceF, Block8, SizeOf (Block8));
  292.                Case Block8.PackType of
  293.                  0: TempRPDHead.DAC := EightBitDMA;
  294.                  1: TempRPDHead.DAC := FourBitDMA;
  295.                  2: TempRPDHead.DAC := TwoSixBitDMA;
  296.                  3: TempRPDHead.DAC := TwoBitDMA;
  297.                end;
  298.                If Block8.Mode = 0 then
  299.                Begin
  300.                  TempRPDHead.Phase := 0;
  301.                  TempRPDHead.Freq := (-256000000 div (Block8.TimeConstant
  302.                                       - 65536));
  303.                End
  304.                Else
  305.                Begin
  306.                  TempRPDHead.Phase := 1;
  307.                  TempRPDHead.Freq := (-256000000 div (Block8.TimeConstant
  308.                                       - 65536));
  309.                End;
  310.              End;
  311.           9: Begin     (* NEW Extended Block (16-Bit/other NEW stuff) *)
  312.                Write ('Converting Block 9.');
  313.                BlockRead (SourceF, Block9, SizeOf (Block9));
  314.                TempRPDHead.Freq := Block9.SamplesPerSec;
  315.                TempRPDHead.DAC := 0;
  316.                Inc (BytesConverted, ThreeByte2Long (Block9.Length));
  317.                Case Block9.FormatTag of
  318.                     $000: TempRPDHead.DAC := EightBitDMA;
  319.                     $001: TempRPDHead.DAC := FourBitDMA;
  320.                     $002: TempRPDHead.DAC := TwoSixBitDMA;
  321.                     $003: TempRPDHead.DAC := TwoBitDMA;
  322.                     $004: Begin
  323.                             TempRPDHead.DAC := SixteenBitDMA;
  324.                             WriteLn ('HA! Sixteen Bit DAC found!');
  325.                           End;
  326.                     (* All other types are undefined in my program as of now!*)
  327.                     (* These will be the Sixteen Bit Compression types       *)
  328.                end;
  329.                TempRPDHead.Phase := (Block9.Channels - 1);
  330.                If TempRPDHead.Phase = 1 then
  331.                  TempRPDHead.Freq := TempRPDHead.Freq * 2;
  332.                LeftToGo := ThreeByte2Long (Block9.Length) - 12;
  333.                Repeat
  334.                 If LeftToGo > $FFFF then
  335.                 Begin
  336.                   Dec (LeftToGo, $FFFF);
  337.                   BlockRead (SourceF, TempBuffer^, $FFFF);
  338.                   BlockWrite (DestF, TempBuffer^, $FFFF);
  339.                 End
  340.                 Else
  341.                 Begin
  342.                   BlockRead (SourceF, TempBuffer^, LeftToGo);
  343.                   BlockWrite (DestF, TempBuffer^, LeftToGo);
  344.                   LeftToGo := 0;
  345.                 End;
  346.                 Write ('.');
  347.               Until LeftToGo = 0;
  348.               WriteLn;
  349.               WriteLn ('Block Type 9: ', ThreeByte2Long (Block9.Length) - 12,
  350.                        ' bytes converted.');
  351.              End;
  352.     end;
  353.   Until Done;
  354.   TempRPDHead.Size := BytesConverted;
  355.   FreeMem (TempBuffer, $FFFF);
  356.   Seek (DestF, 0);
  357.   (* Now, write the completed information... *);
  358.   BlockWrite (DestF, TempRPDHead, SizeOf (TempRPDHead));
  359.   Close (SourceF);
  360.   Close (DestF);
  361.   WriteLn ('File conversion done...');
  362.   WriteLn ('***************************************************');
  363.   Write ('Mode: ');
  364.   Case TempRPDHead.Phase of
  365.     0: WriteLn ('Mono');
  366.     1: WriteLn ('Stereo');
  367.   end;
  368.   Case TempRPDHead.Dac of
  369.        EightBitDMA: WriteLn ('8 Bit (unpacked)');
  370.        FourBitDMA: WriteLn ('4 Bit (packed)');
  371.        FourBitRefDMA: WriteLn ('4 Bit w/Reference Byte (packed)');
  372.        TwoSixBitDMA: WriteLn ('2.6 Bit (packed)');
  373.        TwoSixBitRefDMA: WriteLn ('2.6 Bit w/Reference Byte (packed)');
  374.        TwoBitDMA: WriteLn ('2 Bit (packed)');
  375.        TwoBitRefDMA: WriteLn ('2 Bit w/Reference Byte (packed)');
  376.   end;
  377.   If TempRPDHead.Phase = 1 then TempRPDHead.Freq := TempRPDHead.Freq div 2;
  378.   WriteLn ('Frequency:  ', TempRPDHead.Freq, ' Hz');
  379.   WriteLn ('***************************************************');
  380. End;
  381.  
  382. Function FileExists (Filename: String): Boolean;
  383. var
  384.  F: file;
  385. Begin
  386.  {$I-}
  387.  Assign(F, FileName);
  388.  FileMode := 0;      (* Set file access to read only *)
  389.  Reset(F);
  390.  Close(F);
  391.  {$I+}
  392.  FileExists := (IOResult = 0) and (FileName <> '');
  393. End;
  394.  
  395. Begin
  396.   Clrscr;
  397.   WriteLn ('           VOC2RPD version 1.13, By: Romesh Prakashpalan, 1994');
  398.   WriteLn ('                            VOC2RPD is FREEWARE             ');
  399.   Write ('Enter in VOC file to be converted: ');
  400.   ReadLn (Source);
  401.   If not FileExists (Source) then
  402.   Begin
  403.     WriteLn ('Source File Doesn''t Exist!');
  404.     Halt;
  405.   End;
  406.   Write ('Enter in RPD file to convert to: ');
  407.   ReadLn (Destination);
  408.   If FileExists (Destination) then
  409.   Begin
  410.     Write ('File exists! overwrite? (''N'' for No, any other key kills it): ');
  411.     Ch := UpCase (Readkey);
  412.     WriteLn (Ch);
  413.     If Ch = 'N' then Halt;
  414.   End;
  415.   ConvertVOC2RPD (Source, Destination);
  416. End.